package com.shadow.demo.dictionary.common;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * 日期工具类
 *
 * @author penggch
 *
 */
public class DateUtil {

    public static final String NORM_DATETIME_PATTERN = "yyyy-MM-dd HH:mm:ss";
    public static final String NORM_DATE_PATTERN = "yyyy-MM-dd";
    public static final String NORM_TIME_PATTERN = "HH:mm:ss";
    private static Pattern PATTERN_DATETIME;
    private static Pattern PATTERN_TIMEZONE;
    private static Pattern PATTERN_NUMBER;
    private static Pattern PATTERN_DATE;
    private static Pattern PATTERN_Chinese;

    static {
        PATTERN_DATETIME = Pattern.compile(
                "^((-?\\d{4})-?(\\d{2})-?(\\d{2}))?(T(\\d{2}):?(\\d{2}):?(\\d{2})\\.?(\\d*)?)?(Z|([+-])(\\d{2}):?((\\d{2})?)?)?$");
        PATTERN_TIMEZONE = Pattern.compile("([+-])?(\\d{2}):?((\\d{2})?)?");
        PATTERN_NUMBER = Pattern.compile("^-?\\d*$");
        PATTERN_DATE = Pattern.compile("^[1-9][0-9][0-9][0-9][0-1][0-9][0-3][0-9]$");
        PATTERN_Chinese = Pattern.compile("[\u4e00-\u9fa5]");
    }

    public static Date parse(String dateStr) {
        if (dateStr == null || dateStr.length() == 0) {
            return null;
        }
        Matcher m = PATTERN_Chinese.matcher(dateStr);
        if (m.find()) {
            return null;
        }
        if (PATTERN_DATE.matcher(dateStr).find()) {
            try {
                return getSdfYmd().parse(dateStr);
            } catch (ParseException e) {
                throw new RuntimeException(e);
            }

        } else if (PATTERN_NUMBER.matcher(dateStr).find()) {
            long dateLong = ParseUtil.getLong(dateStr, null);
            Calendar calendar = Calendar.getInstance();
            calendar.setTimeInMillis(dateLong);
            return calendar.getTime();

        }

        int year = 0;
        int month = 0;
        int day = 0;

        int hour = 0;
        int minute = 0;
        int second = 0;
        int millSecond = 0;

        boolean hasTimeZone = false;
        String tzMark = null;
        int tzHour = 0;
        int tzMinute = 0;

        Matcher matcher = PATTERN_DATETIME.matcher(dateStr);
        if (matcher.find()) {
            // 日期
            year = ParseUtil.getInteger(matcher.group(2), 0);
            month = ParseUtil.getInteger(matcher.group(3), 0) - 1;
            day = ParseUtil.getInteger(matcher.group(4), 0);

            // 时间
            hour = ParseUtil.getInteger(matcher.group(6), 0);
            minute = ParseUtil.getInteger(matcher.group(7), 0);
            second = ParseUtil.getInteger(matcher.group(8), 0);
            millSecond = ParseUtil.getInteger(matcher.group(9), 0);

            // 时区
            if (matcher.group(10) != null && matcher.group(10).length() != 0) {
                hasTimeZone = true;
                tzMark = matcher.group(11);
                tzHour = ParseUtil.getInteger(matcher.group(12), 0);
                tzMinute = ParseUtil.getInteger(matcher.group(13), 0);
            }
        } else {
            int tzIndex = -1;
            if (tzIndex == -1)
                tzIndex = dateStr.indexOf("GMT");
            if (tzIndex == -1)
                tzIndex = dateStr.indexOf("UTC");
            if (tzIndex == -1)
                tzIndex = dateStr.indexOf("CST");
            String timeZone = null;
            if (tzIndex != -1) {
                hasTimeZone = true;
                timeZone = dateStr.substring(tzIndex + 3);
                dateStr = dateStr.substring(0, tzIndex);
            }

            String[] da = dateStr.split("[^0-9]+");
            if (da.length > 0)
                year = ParseUtil.getInteger(da[0], 0);
            if (da.length > 1)
                month = ParseUtil.getInteger(da[1], 0) - 1;
            if (da.length > 2)
                day = ParseUtil.getInteger(da[2], 0);
            if (da.length > 3)
                hour = ParseUtil.getInteger(da[3], 0);
            if (da.length > 4)
                minute = ParseUtil.getInteger(da[4], 0);
            if (da.length > 5)
                second = ParseUtil.getInteger(da[5], 0);
            if (da.length > 6)
                millSecond = ParseUtil.getInteger(da[6], 0);

            if (hasTimeZone) {
                Matcher tzMatcher = PATTERN_TIMEZONE.matcher(timeZone);
                if (tzMatcher.find()) {
                    tzMark = tzMatcher.group(1);
                    tzHour = ParseUtil.getInteger(tzMatcher.group(2), 0);
                    tzMinute = ParseUtil.getInteger(tzMatcher.group(3), 0);
                }
            }
        }
        if (month > 11 || day > 31 || hour > 23 || minute > 59 || second > 59) {
            return null;
        }

        Calendar calendar = Calendar.getInstance();

        // 设置时刻
        calendar.set(Calendar.YEAR, year);
        calendar.set(Calendar.MONTH, month);
        calendar.set(Calendar.DAY_OF_MONTH, day);
        calendar.set(Calendar.HOUR_OF_DAY, hour);
        calendar.set(Calendar.MINUTE, minute);
        calendar.set(Calendar.SECOND, second);
        calendar.set(Calendar.MILLISECOND, millSecond);

        // 处理时区偏移
        if (hasTimeZone) {
            int offsetMinute = tzHour * 60 + tzMinute;
            if (tzMark != null && tzMark.equals("-")) {
                offsetMinute = 0 - offsetMinute;
            }
            offsetMinute = calendar.getTimeZone().getOffset(0l) / 60000 - offsetMinute;
            calendar.add(Calendar.MINUTE, offsetMinute);
        }

        return calendar.getTime();
    }

    /**
     * 格式化日期
     *
     * @param date         日期
     * @param formatString 格式
     * @return
     */
    public static String format(Date date, String formatString) {
        if (date == null) {
            return null;
        }
        SimpleDateFormat sdf = new SimpleDateFormat(formatString);
        return sdf.format(date);
    }

    /**
     * 格式化日期字符串
     *
     * @param dateStr      日期字符串
     * @param formatString 格式
     * @return
     */
    public static String formatDateString(String dateStr, String formatString) {
        Date date = parse(dateStr);
        return format(date, formatString);
    }

    public static String formatDate(Date date) {
        if (date == null) {
            return null;
        }
        return getSdfDate().format(date);
    }

    public static String formatTime(Date date) {
        if (date == null) {
            return null;
        }
        return getSdfTime().format(date);
    }

    public static String formatDateTime(Date date) {
        if (date == null) {
            return null;
        }
        return getSdfDatetime().format(date);
    }

    public static String formatLongDate(Date date) {
        if (date == null) {
            return null;
        }
        return getSdfLongDate().format(date);
    }

    public static String formatLongTime(Date date) {
        if (date == null) {
            return null;
        }
        return getSdfLongTime().format(date);
    }

    public static String formatLongDateTime(Date date) {
        if (date == null) {
            return null;
        }
        return getSdfLongDatetime().format(date);
    }

    public static String formatISODateTime(Date date) {
        if (date == null) {
            return null;
        }
        return getSdfIsoDatetime().format(date);
    }

    public static Date getYearStart(int year) {
        try {
            return getSdfDate().parse(year + "-01-01");
        } catch (ParseException e) {
            throw new RuntimeException(e);
        }
    }

    public static Date getSysTime() {
        return Calendar.getInstance().getTime();
    }

    /**
     * 标准日期格式:yyyyMMdd
     * @return
     */
    public static SimpleDateFormat getSdfYmd() {
        return  new SimpleDateFormat("yyyyMMdd");
    }

    /**
     * 标准日期格式：yyyy-MM-dd
     */
    public static SimpleDateFormat getSdfDate() {
        return  new SimpleDateFormat("yyyy-MM-dd");
    }

    /**
     * 标准时间格式：HH:mm:ss
     */
    public static SimpleDateFormat getSdfTime() {
        return  new SimpleDateFormat("HH:mm:ss");
    }

    /**
     * 标准日期时间格式，精确到秒：yyyy-MM-dd HH:mm:ss
     */
    public static SimpleDateFormat getSdfDatetime() {
        return  new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
    }

    /**
     * 标准日期时间格式:yyyy年MM月dd日
     * @return
     */
    public static SimpleDateFormat getSdfLongDate() {
        return new SimpleDateFormat("yyyy年MM月dd日");
    }

    /**
     * 标准日期时间格式:HH时mm分ss秒
     * @return
     */
    public static SimpleDateFormat getSdfLongTime() {
        return  new SimpleDateFormat("HH时mm分ss秒");
    }

    /**
     *  标准日期时间格式:yyyy年MM月dd日 HH时mm分ss秒
     * @return
     */
    public static SimpleDateFormat getSdfLongDatetime() {
        return  new SimpleDateFormat("yyyy年MM月dd日 HH时mm分ss秒");
    }

    /**
     *  标准日期时间格式:yyyy-MM-dd'T'HH:mm:ss.SSSZ
     * @return
     */
    public static SimpleDateFormat getSdfIsoDatetime() {
        return new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSZ");
    }
}
